home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume3 / pcmail / part01 next >
Encoding:
Internet Message Format  |  1989-02-03  |  56.6 KB

  1. Path: xanth!mcnc!uvaarpa!umd5!purdue!decwrl!decvax!mandrill!hal!ncoast!allbery
  2. From: wswietse@eutrc3.UUCP (Wietse Venema)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i002: uucp mail for pc's (1 of 8)
  5. Message-ID: <210@eutrc3.UUCP>
  6. Date: 20 Apr 88 16:40:21 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: wswietse@eutrc3.UUCP (Wietse Venema)
  9. Organization: Tech. Univ. Eindhoven, Neth.
  10. Lines: 1653
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. comp.sources.misc: Volume 3, Issue 2
  14. Submitted-By: "Wietse Venema" <wswietse@eutrc3.UUCP>
  15. Archive-Name: pcmail/Part1
  16.  
  17. These programs turn a pc into a (non-routing) uucp node. The
  18. programs run under MS-DOS and various flavours of UNIX. Porting
  19. to other OSes should not be difficult.
  20.  
  21. #! /bin/sh
  22. # This is a shell archive.  Remove anything before this line, then unpack
  23. # it by saving it into a file and typing "sh file".  To overwrite existing
  24. # files, type "sh file -c".  You can also feed this as standard input via
  25. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  26. # will see the following message at the end:
  27. #        "End of archive 1 (of 8)."
  28. # Contents:  README termcap comport.s hsearch.c hsearch.h pager.c
  29. # Wrapped by wietse@eutwc1 on Wed Apr 20 16:45:03 1988
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f README -a "${1}" != "-c" ; then 
  32.   echo shar: Will not over-write existing file \"README\"
  33. else
  34. echo shar: Extracting \"README\" \(2251 characters\)
  35. sed "s/^X//" >README <<'END_OF_README'
  36. XGENERAL
  37. X
  38. XThe pc-mail software provides a single user with  facilities  for
  39. Xcreating,  sending and receiving electronic mail messages via the
  40. Xuucp network. The programs were developed under UNIX but also run
  41. Xwith MS-DOS. Porting to other OSes should be relatively easy.
  42. X
  43. XFor the non-technical user there is a menu-driven shell that  au-
  44. Xtomatically  invokes  various utility programs, e.g. an editor of
  45. Xthe user's choice for editing or  creating  messages,  a  program
  46. Xthat logs in on a UNIX host to exchange files and so on. Any edi-
  47. Xtor that produces clean ASCII files can be used  (wordstar  files
  48. Xare  also handled correctly).  Other facilities: alias data base,
  49. Xbatch-mode operation.
  50. X
  51. XMore technically oriented users will want to avoid  the  interac-
  52. Xtive  shell  and  use  the  mail  data  base and utility programs
  53. Xdirectly. The necessary information can be found in the implemen-
  54. Xtation  documentation. In adition, almost every source file has a
  55. Xbuilt-in manual page.  The  latter  can  be  extracted  with  the
  56. Xsrctoman.sh shell script.
  57. X
  58. XThe programs have been tested under MS-DOS on XT  and  AT  clones
  59. X(MicroSoft  V4  C compiler), and with Microport System-V. For the
  60. Xinteractive shell, a tiny MS-DOS termcap library is provided.  It
  61. Xrequires the ANSI.SYS tty driver (or better) to work sucessfully.
  62. XIn order to run the software under UNIX  (for  testing  purposes)
  63. Xone  needs  a  C  library  with  the  System-V  library functions
  64. X(strtok(), memcpy() et  al.).  Morever,  the  directory  scanning
  65. Xfunctions  only work with file systems that use fixed-size direc-
  66. Xtory entries (i.e. not BSD).
  67. X
  68. XThe programs support the sending and receiving of electronic mail
  69. Xonly;  no  transfer  of  files by name and no message routing. In
  70. Xfact the pc side treats each data file it receives as a mail mes-
  71. Xsage,  irrespective  of  its  actual  destination. The reason for
  72. Xthese limitations are (besides uucp security problems)  that  all
  73. Xfiles  can be sent as mail, and that a pc does not provide multi-
  74. Xuser support anyway.
  75. X
  76. XYou can do anything with the source, but not ask money for it nor
  77. Xremove  references to the original authors. Complaints, feedback,
  78. Xsuggestions are welcome.
  79. X
  80. X    Wietse Venema    uucp:    mcvax!eutrc3!wswietse
  81. X            bitnet:    wswietse@heitue5
  82. END_OF_README
  83. if test 2251 -ne `wc -c <README`; then
  84.     echo shar: \"README\" unpacked with wrong size!
  85. fi
  86. # end of overwriting check
  87. fi
  88. if test ! -d termcap ; then
  89.     echo shar: Creating directory \"termcap\"
  90.     mkdir termcap
  91. fi
  92. if test -f comport.s -a "${1}" != "-c" ; then 
  93.   echo shar: Will not over-write existing file \"comport.s\"
  94. else
  95. echo shar: Extracting \"comport.s\" \(20454 characters\)
  96. sed "s/^X//" >comport.s <<'END_OF_comport.s'
  97. Xtitle IBM PC Communications I/O Routines 
  98. X;
  99. X; @(#) comport.asm      Version hoptoad-1.3     87/03/24
  100. X;
  101. X; Orginal code -- Curt Klinsing
  102. X;
  103. X; Changes and updates -- Copyright (c) 1987 Tim Pozar
  104. X; Anyone can use this code for anything, but it is copyright by Tim
  105. X; and you must leave his copyright in the code.
  106. X;
  107. X; ver: 0
  108. X; rev: 2
  109. X; March 13th 1987
  110. X; This code is in a very early stage and should not be let out.
  111. X; Several other extensive functions are planned as well as changes
  112. X; to the current code.
  113. X;
  114. X; 2/20/87 
  115. X;   Changed segment declarations and function names (eg. _function)
  116. X; to fit Microsoft C 4.0 and linker requirements.
  117. X;
  118. X; FUNCTIONS CHANGED/ADDED --
  119. X; set_tty(port_number)
  120. X;   Function to find current settings of the port and set up serial 
  121. X; port for 'baud' and 'lcbyte', and enable DTR.  This will set up the
  122. X; port number base addressed passed to it (eg. 3F8h) and all functions
  123. X; will use this port until the function is used again. (NOT READY FOR USE)
  124. X;
  125. X; reset_tty()
  126. X;   Function to put the port back into the state it was when it was 
  127. X; first found by set_tty().  If set_tty() was not called it will not 
  128. X; change the settings of the port. (NOT READY FOR USE)
  129. X;
  130. X; 3/13/87
  131. X; get_msr()
  132. X;   Function to read (get) the byte located in the Modem Status 
  133. X; Register (3FEh).  The table below describes the byte returned.
  134. X;   bit  description
  135. X;    0   Delta Clear to Send (DCTS)
  136. X;        Indicates that the !CTS input to the chip has changed state
  137. X;        since the last time it was read by the processor.
  138. X;    1   Delta Data Set Ready (DDSR)
  139. X;        Indicates that the !DRS input to the chip has changed since 
  140. X;        last time it was read by the processor.
  141. X;    2   Trailing Edge Ring Indicator (TERI)
  142. X;        Indicates that the !RI input to the chip has changed from
  143. X;        an on (logical 1) to an off (logical 0) condition.
  144. X;    3   Delta Rx Line Signal detect (DRLSD)
  145. X;        Indicates that the !RLSD input to the chip has changed state.
  146. X; NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status
  147. X;       interrupt is generated.
  148. X;
  149. X;    4   Clear to Send (CTS)
  150. X;        This bit is the complement of the clear to send (!CTS) input.
  151. X;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  152. X;        equivalent to RTS in the MCR.
  153. X;    5   Data Set Ready (DSR)
  154. X;        This bit is the complement of the data set ready (!DSR) input.
  155. X;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  156. X;        equivalent to DTR in the MCR.
  157. X;    6   Ring Indicator (RI)
  158. X;        This bit is the complement of the ring indicator (!RI) input.
  159. X;        If bit 4 (LOOP) of the MCR is set to a logical 1, this is 
  160. X;        equivalent to OUT 1 in the MCR.
  161. X;    7   Receive Line Signal Detect (RLSD).
  162. X;        This bit is the complement of the received line signal detect
  163. X;        (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1,
  164. X;        this is equivalent to OUT 2 in the MCR.
  165. X;
  166. X;   Currently this driver is set up for COM1 (3f8h).
  167. X;   If you are using the interupt driven buffer, take out the code 
  168. X; that enables the DTR so that it doesn't get raised until the vectors
  169. X; are initilized. 
  170. X;
  171. X; 22/04/1987 W.Z. Venema 
  172. X;       set_tty()       baud rate parameter (values as the "baud" macro below)
  173. X;       uninit_comm()   don't drop DTR when done
  174. X;
  175. X; 19/05/1987 W.Z. Venema
  176. X;       outp_char()     made it check for Xon/Xoff from other system
  177. X
  178. X_TEXT   SEGMENT BYTE PUBLIC 'CODE'
  179. X_TEXT   ENDS
  180. X_DATA   SEGMENT BYTE PUBLIC 'DATA'
  181. X_DATA   ENDS
  182. XCONST   SEGMENT BYTE PUBLIC 'CONST'
  183. XCONST   ENDS
  184. X_BBS    SEGMENT BYTE PUBLIC 'BBS'
  185. X_BBS    ENDS
  186. X
  187. XDGROUP  GROUP   CONST, _BBS, _DATA
  188. X      ASSUME    CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
  189. X
  190. X_TEXT      SEGMENT
  191. X;
  192. X;A set of Lattice C and MSC callable functions to support
  193. X;interrupt driven character I/O on the  IBM PC. Input
  194. X;is buffered, output is polled.
  195. X;
  196. X;added functions (TMP) --
  197. Xpublic  _set_tty        ;find current settings, and initialize 
  198. X                        ;comm port to 8 bits and set DTR
  199. Xpublic  _reset_tty      ;reset to settings that set_tty() found
  200. Xpublic  _get_msr        ;get MSR byte from port.
  201. X;
  202. X;original functions --
  203. Xpublic  _init_comm      ;initialize the comm port interupts,
  204. Xpublic  _uninit_comm    ;remove initialization,
  205. Xpublic  _set_xoff       ;enable/disable XON/XOFF,
  206. Xpublic  _get_xoff       ;read XON/XOFF state,
  207. Xpublic  _rcvd_xoff      ;returns true if XOFF rcvd,
  208. Xpublic  _sent_xoff      ;true if XOFF sent,
  209. Xpublic  _inp_cnt        ;returns count of rcv chars,
  210. Xpublic  _inp_char       ;get one char from buffer,
  211. Xpublic  _inp_flush      ;flush input buffer,
  212. Xpublic  _outp_char      ;output a character,
  213. X;
  214. X;A better description can be found in the comment
  215. X;block  in each function.
  216. X;
  217. X;       assume  cs:pgroup
  218. X;
  219. XFALSE   EQU     0
  220. XTRUE    EQU     NOT FALSE
  221. X;
  222. XBASE    EQU     03F8H   ;BASE FOR SERIAL BOARD
  223. X;
  224. XLCR     equ     BASE+3  ; Line control register
  225. XIER     equ     BASE+1  ; Interrup Enable Register
  226. XMCR     EQU     BASE+4  ;modem control register
  227. XMDMSTA  EQU     BASE+5  ;line status register
  228. XMDMMSR  EQU     BASE+6  ;modem status register
  229. XMDMBAD  EQU     BASE    ;lsb baud resgister
  230. XEnblDRdy equ    01H     ; enable 'data-ready' interrupt bit
  231. XIntCtlr  EQU    21H     ;OCW 1 FOR 8259 CONTROLLER
  232. XEnblIRQ4 EQU    0EFH    ;Enable COMMUNICATIONS (IRQ4)
  233. Xdataport EQU    BASE    ;transmit/receive data port
  234. XMaskIRQ4 EQU    10H     ;BIT TO DISABLE COMM INTERRUPT (IRQ4)
  235. X
  236. XMDMCD   EQU     80H     ;mask for carrier dectect
  237. XSETBAU  EQU     80H     ;code for Divisor Latch Access Bit
  238. XMDMTBE  EQU     20H     ;8250 tbe flag
  239. XMDMBRK  EQU     40H     ;command code for 8250 break
  240. XLINMOD  EQU     03H     ;line mode=8 bit, no parity
  241. XMDMMOD  EQU     0BH     ;modem mode = DTR and RTS HIGH
  242. XSTOP2   EQU     04H     ;BIT FOR TWO STOP BITS IF BAUD<300
  243. XRS8259  EQU     20H     ;OCW 3 FOR 8259
  244. XRSTINT  EQU     64H     ;SPECIFIC EOI FOR COMM INTERRUPT 
  245. XXOFF    EQU     13H     ;XOFF character
  246. XXON     EQU     11H     ;XON character
  247. X;
  248. X;       MISCELLANEOUS EQUATES
  249. X;
  250. XCR      EQU     13
  251. XLF      EQU     10
  252. XDosCall EQU     33      ;INTERRUPT NUMBER FOR DOS CALL  
  253. XCNSTAT  EQU     11      ;FUNCTION NUMBER FOR CONSOLE STATUS
  254. XCNIN    EQU     1       ;FUNCTION NUMBER FOR CONSOLE INPUT
  255. XBUFSIZ  EQU     512     ;Max NUMBER OF CHARS
  256. XSetIntVect  EQU 25H     ;SET INTERRUPT VECTOR FUNCTION NUMBER
  257. X
  258. X;
  259. X; Communication parameters --
  260. X;
  261. Xbaud    equ     12      ; 1047 =  110 (are you kidding?)
  262. X                        ;  384 =  300
  263. X                        ;   96 = 1200
  264. X                        ;   48 = 2400
  265. X                        ;   24 = 4800
  266. X                        ;   12 = 9600
  267. Xparity  equ     00000b  ;00000 = none
  268. X                        ;01000 = odd
  269. X                        ;11000 = even
  270. Xstopbit equ     000b    ;  000 = 1 bit
  271. X                        ;  100 = 2 bits
  272. Xwordlth equ     11b     ;   10 = 7 bits
  273. X                        ;   11 = 8 bits
  274. Xlcbyte  equ     parity+stopbit+wordlth      ;line control byte
  275. Xdiv_on  equ     80h     ;divisor latch access bit (DLAB)
  276. X
  277. X;
  278. X;       DUMP BUFFER, COUNT AND POINTER.  
  279. X;
  280. XCIRC_BUF DB     BUFSIZ DUP(?)   ;ALLOW 512 MaxIMUM BUFFERED CHARACTERS
  281. XBUF_TOP EQU     $ - 1           ;KEEP TRACK OF THE TOP OF THE BUFFER
  282. XCIRC_TOP DW     BUF_TOP         ;
  283. X;
  284. XCIRC_IN DW      OFFSET CIRC_BUF ;POINTER TO LAST CHAR. PLACED IN BUFFER
  285. XCIRC_CUR DW     OFFSET CIRC_BUF ;POINTER TO NEXT CHAR. TO BE RETRIEVED FROM
  286. X                                ; BUFFER
  287. XCIRC_CT DW      0               ;COUNT OF CHARACTERS USED IN BUFFER
  288. XSNT_XOFF DB     FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN SEND
  289. XGOT_XOFF  DB    FALSE           ;FLAG TO CHECK IF AN XOFF HAS BEEN RECEIVED
  290. XSEE_XOFF  DB    FALSE           ;FLAT TO SEE IF WE ARE INTERESTED IN XON/XOFF
  291. X;
  292. X;
  293. X; set_tty()
  294. X;
  295. X_set_tty proc near
  296. X        push    bp
  297. X        mov     bp,sp           ; wzv C calling standard
  298. X;        mov     dx,mcr
  299. X;        in      al,dx           ; get modem parameters
  300. X;        mov     MCR_BYTE,al     ; save them
  301. X        mov     dx,lcr
  302. X;        in      al,dx           ; get line parameters
  303. X;        mov     LCR_BYTE,al     ; save them
  304. X        mov     al,div_on
  305. X        out     dx,al           ; set 8250 for baud rate selection
  306. X        ; can the baud rate divisor be read to save the settings?
  307. X        ; if so, stick the code here.
  308. X        mov     ax,[bp+4]       ; was mov ax,baud /wzv
  309. X        mov     dx,mdmbad
  310. X        out     dx,al           ; low byte divisor
  311. X        mov     al,ah
  312. X        inc     dx
  313. X        out     dx,al           ; high byte divisor
  314. X        mov     dx,lcr
  315. X        mov     al,lcbyte
  316. X        out     dx,al           ; set line control reg.
  317. X        mov     dx,mcr
  318. X        in      al,dx
  319. X        or      al,mdmmod
  320. X        out     dx,al           ; set DTR high
  321. Xflsh:   mov     dx,dataport
  322. X        in      al,dx
  323. X        mov     dx,mdmsta
  324. X        in      al,dx
  325. X        and     al,1
  326. X        jnz     flsh
  327. X      
  328. X        pop     bp
  329. X        ret
  330. X
  331. X_set_tty endp
  332. X
  333. X
  334. X_reset_tty proc near
  335. X        push    bp
  336. X
  337. X        pop     bp
  338. X        ret
  339. X
  340. X_reset_tty endp
  341. X
  342. X_get_msr proc near
  343. X        push    bp
  344. X        push    ds              ; save data segment
  345. X        push    cs
  346. X        pop     ds
  347. X
  348. X        xor     ax,ax
  349. X        mov     dx,MDMMSR
  350. X        in      al,dx
  351. X
  352. X        pop     ds
  353. X        pop     bp
  354. X        ret
  355. X
  356. X_get_msr endp
  357. X
  358. X;
  359. X; set_xoff(flag)         Enable (flag != 0) or disable
  360. X;int flag;              (flag == 0) XON/ XOFF protocol
  361. X;                       for the character input stream.
  362. X;If enabled, an XOFF will be sent when  the buffer
  363. X;reaches 3/4 full. NOTE: an XON will not be sent auto-
  364. X;matically. Your program must do it when it sees
  365. X;the _rcvd_xoff() flag,  and ready for more chars.
  366. X;
  367. X_set_xoff proc near
  368. X        push    bp
  369. X        mov     bp,sp           ; wzv C calling standard
  370. X        PUSH    DS              ;SAVE DATA SEGMENT
  371. X        mov     bx,[bp+4]       ; wzv C calling standard
  372. X        push    cs
  373. X        pop     ds              ; move code seg addr to data seg reg.
  374. X        cmp     bx,0
  375. X        jnz     to_on
  376. X        mov     see_xoff,FALSE
  377. X        jmp     done1
  378. Xto_on:  mov     see_xoff,TRUE
  379. Xdone1:  pop     ds
  380. X        pop     bp
  381. X        ret
  382. X_set_xoff endp
  383. X;
  384. X;flag = get_xoff()      Returns the current setting
  385. X;                       of the XON/ XOFF flag set
  386. X;by set_xoff(), above.
  387. X;
  388. X_get_xoff proc near
  389. X        push    bp
  390. X        push    ds              ; save data reg
  391. X        push    cs
  392. X        pop     ds              ; move code seg addr to data seg reg.
  393. X        xor     ax,ax
  394. X        mov     al,see_xoff
  395. X        pop     ds
  396. X        pop     bp
  397. X        ret
  398. X_get_xoff endp
  399. X;
  400. X;flag = sent_xoff();    Returns true if an XOFF
  401. X;                       character was sent, indicating
  402. X;the receive buffer is  3/4 full.
  403. X;
  404. X_sent_xoff proc  near
  405. X        push    bp
  406. X        push    ds              ; save data reg
  407. X        push    cs
  408. X        pop     ds              ; move code seg addr to data seg reg.
  409. X        xor     ax,ax
  410. X        mov     al,snt_xoff
  411. X        pop     ds
  412. X        pop     bp
  413. X        ret
  414. X_sent_xoff endp
  415. X;
  416. X; rcvd_xoff()            Returns true if an XOFF was
  417. X;                       received; will return false as
  418. X;soon as an XON is received. Does not effect data output,
  419. X;only indicates the above. (Obviously useless for binary
  420. X;data.)
  421. X;
  422. X_rcvd_xoff proc  near
  423. X        push    bp
  424. X        push    ds              ; save data reg
  425. X        push    cs
  426. X        pop     ds              ; move code seg addr to data seg reg.
  427. X        xor     ax,ax
  428. X        mov     al,got_xoff
  429. X        pop     ds              ; restore data reg
  430. X        pop     bp
  431. X        ret
  432. X_rcvd_xoff endp
  433. X;
  434. X;count = inp_cnt()       Returns the number of characters
  435. X;                       available in the input buffer.
  436. X;
  437. X
  438. X_inp_cnt proc near       
  439. X        push    bp
  440. X        push    ds              ; save data segment
  441. X        push    cs
  442. X        pop     ds              ; move code seg addr to data seg reg
  443. X        mov     ax,circ_ct
  444. X        pop     ds
  445. X        pop     bp
  446. X        ret
  447. X_inp_cnt endp
  448. X;
  449. X; inp_flush()    Flush the input buffer.
  450. X;
  451. X_inp_flush proc  near    
  452. X        push    bp
  453. X        push    ds              ; save data reg
  454. X        push    cs
  455. X        pop     ds              ; move code seg addr to data seg reg.
  456. X        mov     bx,offset circ_buf
  457. X        mov     circ_in,bx      
  458. X        mov     circ_cur,bx
  459. X        xor     ax,ax
  460. X        mov     circ_ct,ax
  461. X        pop     ds
  462. X        pop     bp
  463. X        ret
  464. X_inp_flush endp
  465. X
  466. X; --------- Init -----------------------------------
  467. X; Program initialization:
  468. X;   --  Set up vector for RS232 interrupt (0CH)
  469. X;   --  Enbl IRQ4
  470. X;   --  Enbl RS232 interrupt on data ready
  471. X;
  472. X; ---------------------------------------------------
  473. X
  474. X_init_comm proc  near
  475. X        push    bp
  476. X        cli
  477. X
  478. X;  ---- Set up  INT x'0C' for IRQ4
  479. X
  480. X        push    ds
  481. X        push    cs
  482. X        pop     ds              ;cs to ds
  483. X        mov     dx,offset IntHdlr ;relative adddres of interrupt handler
  484. X        mov     al,0cH          ;interrupt number for comm.
  485. X        mov     ah,SetIntVect   ;function number for setting int vector
  486. X        int     DosCall         ;set interrupt in 8086 table
  487. X        pop     ds              ;restore DS
  488. X
  489. X;  ---- Enbl IRQ4 on 8259 interrupt controller
  490. X
  491. X        cli
  492. X
  493. X        in      al,IntCtlr      ; get current masks 
  494. X        and     al,EnblIRQ4     ; Reset IRQ4 mask
  495. X        out     IntCtlr,al      ; And restore to IMR
  496. X
  497. X;  ---   Enbl 8250 data ready interrupt
  498. X
  499. X        mov     dx,LCR          ; DX ==> LCR
  500. X        in      al,dx           ; Reset DLAB for IER access
  501. X        and     al,7FH
  502. X        out     dx,al
  503. X        mov     dx,IER          ; Interrupt Enbl Register
  504. X        mov     al,EnblDRdy     ; Enable 'data-ready' interrupt
  505. X        out     dx,al
  506. X
  507. X;  ---   Enbl OUT2 on 8250
  508. X
  509. X        mov     dx,MCR          ; modem control register        
  510. X        in      al,dx           ; Enable OUT2
  511. X        or      al,08h            ; find out what is in there and
  512. X        out     dx,al            ; enable the DTR
  513. X
  514. X        sti
  515. X
  516. X        pop     bp
  517. X        ret
  518. X_init_comm endp
  519. X;
  520. X; uninit_comm()          Removes the interrupt structure
  521. X;                       installed by _init_comm(). Must be
  522. X;done before passing control to the DOS, else chars received
  523. X;will be stored into the next program loaded!
  524. X;
  525. X_uninit_comm proc near
  526. X        push    bp
  527. X; ---   Disable IRQ4 on 8259
  528. X
  529. X        cli
  530. X        in      al,IntCtlr      ;GET OCW1 FROM 8259
  531. X        or      al,MaskIRQ4     ;DISABLE COMMUNICATIONS INTERRUPT
  532. X        out     IntCtlr,al
  533. X
  534. X; ---   Disable 8250 data ready interrupt
  535. X        
  536. X        mov     dx,LCR          ; DX ==> LCR
  537. X        in      al,dx           ; Reset DLAB for IER access
  538. X        and     al,7FH
  539. X        out     dx,al
  540. X        mov     dx,IER          ; Interrupt Enbl Register
  541. X        mov     al,0            ; Disable all 8250 interrupts
  542. X        out     dx,al
  543. X
  544. X;  ---   Disable OUT2 on 8250
  545. X
  546. X        mov     dx,MCR          ; modem control register        
  547. X        mov     al,1            ; Disable OUT2 /wzv use 1 instead of 0
  548. X        out     dx,al
  549. X
  550. X        sti
  551. X        pop     bp
  552. X        ret
  553. X_uninit_comm endp
  554. X;
  555. X;char  inp_char()      Return a character from the input
  556. X;                      buffer. Assumes you have called
  557. X;inp_cnt() to see if theres any characters to get.
  558. X;
  559. X_inp_char proc near      
  560. X        push    bp
  561. X        push    ds              ; save data reg
  562. X        push    cs
  563. X        pop     ds              ; move code seg addr to data seg reg.
  564. X        mov     bx,circ_cur
  565. X        xor     ax,ax
  566. X        mov     al,[bx]         ;get next char from circ_buf
  567. X        DEC     circ_ct         ;decrement circ_buf COUNT
  568. X        CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  569. X        JZ      reset_cur       ;JUMP IF SO
  570. X        INC     bx              ;ELSE, BUMP PTR
  571. X        JMP SHORT upd_cur
  572. Xreset_cur:
  573. X        mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  574. Xupd_cur:
  575. X        mov     circ_cur,bx             ;SAVE NEW PTR
  576. X        xor     cx,cx
  577. X        mov     cl,see_xoff     ;check if interested in xon/xoff
  578. X        cmp     cl,TRUE
  579. X        jnz     clnup2          ;not interested, so goto return
  580. X        cmp     snt_xoff,TRUE   ;have we sent an xoff?
  581. X        jnz     clnup2          ;no, so return
  582. X        cmp     circ_ct,80h     ;yes, so see in buf is now emptying
  583. X        jg      clnup2          ;not empty enuf to send xon, jump to ret
  584. X        mov     snt_xoff,FALSE
  585. X        mov     cl,XON
  586. X        push    ax              ; save char
  587. X        call    comout
  588. X        pop     ax
  589. Xclnup2: pop     DS              ;GET BACK ENTERING DS
  590. X        pop     bp
  591. X        ret
  592. X_inp_char endp
  593. X;
  594. X; outp_char(c)           Output the character to the
  595. X;char c;                serial port. This is not buffered
  596. X;                       or interrupt driven.
  597. X;
  598. X_outp_char proc  near
  599. X        push    bp
  600. X        mov     bp,sp
  601. X    push    ds        ; save data segment register /wzv
  602. X    push    cs        ; copy code segment register /wzv
  603. X    pop    ds        ; to data segment register /wzv
  604. Xw_Xon:  test    got_Xoff,TRUE    ; shut up if Xoff received / wzv
  605. X        jnz     w_Xon
  606. X        mov     cl,[bp+4]
  607. X        sti
  608. X        call    comout
  609. X    pop    ds        ; restore data segment register / wzv
  610. X        pop     bp
  611. X        ret
  612. X_outp_char endp
  613. X;
  614. X;Local  subroutine: output CL to the port.
  615. X;
  616. Xcomout: mov     dx,MDMSTA       
  617. X        in      al,dx           ; get 8250 status
  618. X        and     al,MDMTBE       ; check for transmitter ready
  619. X        jz      comout          ; jump if not to wait
  620. X        mov     al,cl           ; get char to al
  621. X        mov     dx,dataport     
  622. X        out     dx,al           ; output char to 8251
  623. X        ret
  624. X;
  625. X;       RECEIVE INTERRUPT HANDLER (CHANGED TO PLACE CHARACTERS IN A
  626. X;        CIRCULAR circ_buf AND TO SEND AN XOFF IF THE circ_buf IS MORE THAN
  627. X;        3/4 FULL - S.G.)
  628. X;
  629. XIntHdlr:
  630. X        CLI
  631. X        push    cx
  632. X        push    dx
  633. X        push    bx
  634. X        push    ax
  635. X        push    ds
  636. X        mov     ax,cs           ;get cur code segment
  637. X        mov     ds,ax           ;and set it as data segment
  638. X        mov     bx,circ_in      ;GET circ_buf IN PTR
  639. X        mov     DX,dataport     ;GET DATA PORT NUMBER
  640. X        IN      AL,DX           ;GET RECEIVED CHARACTER
  641. X;       push    ax
  642. X;       push    dx   
  643. X;       xor     ax,ax
  644. X;       xor     dx,dx
  645. X;       mov     dl,al
  646. X;       mov     ah,2
  647. X;       int     DosCall
  648. X;       pop     dx
  649. X;       pop     ax
  650. X        xor     cx,cx
  651. X        mov     cl,see_xoff     ;check if interested in xon/xoff
  652. X        cmp     cl,TRUE
  653. X        jnz     ck_full         ;not interested goto ck if buf full
  654. X        mov     cl,al           ;put char in cl for testing
  655. X        and     cl,7fh          ;turn off any parity bits 
  656. X        cmp     cl,XOFF         ;see if we got an xoff
  657. X        jnz     ck_xon
  658. X        mov     got_Xoff,TRUE   ; code for handling xon/xoff from remote
  659. X        jmp     clnup
  660. Xck_xon: cmp     cl,XON
  661. X        jnz     reg_ch
  662. X        mov     got_Xoff,FALSE
  663. X        jmp     clnup
  664. X;
  665. X;Normal character; not  XON/XOFF, or XON/XOFF disabled.
  666. X;
  667. Xreg_ch: test    snt_Xoff,TRUE   ;SEE IF sentXoff IS SET
  668. X        jnz     ck_full         ;IF SO, DON'T SEND ANOTHER XOFF
  669. X        CMP     circ_ct,(BUFSIZ * 3)/4  ;ALLOW BUF TO BECOME 3/4 FULL BEFORE
  670. X                                        ; SENDING XOFF
  671. X        jb      savch           ;IF IT'S OK, CONTINUE
  672. X        push    ax              ;SAVE CHARACTER
  673. X        mov     CL,XOFF         ;GET XOFF CHARACTER
  674. X        mov     snt_Xoff,TRUE  ;RESET sentXoff
  675. X        call    comout          ; AND SEND IT
  676. X        pop     ax              ;RETRIEVE CHARACTER
  677. X        JMP SHORT savch         ;IF WE'RE HERE, THE circ_buf HAS BUFSIZ-80H
  678. X                                ;  CHARACTERS
  679. Xck_full:
  680. X        CMP     circ_ct,BUFSIZ  ;SEE IF circ_buf ALREADY FULL
  681. X        JZ      clnup           ; JUMP IF SO, DO NOT PLACE CHARACTER IN BFR
  682. Xsavch:                          
  683. X        mov     [bx],AL         ;SAVE NEW CHARACTER IN circ_buf
  684. X        inc     circ_ct         ;BUMP circ_buf COUNT
  685. X        CMP     bx,circ_top     ;ARE WE AT THE TOP OF THE circ_buf?
  686. X        JZ      reset_in        ;JUMP IF SO
  687. X        inc     bx              ;ELSE, BUMP PTR
  688. X        JMP SHORT into_buf
  689. Xreset_in:
  690. X        mov     bx,OFFSET circ_buf      ;RESET circ_in TO BOTTOM OF BUF.
  691. Xinto_buf:
  692. X        mov     circ_in,bx              ;SAVE NEW PTR
  693. Xclnup:
  694. X        mov     AL,RSTINT
  695. X        OUT     RS8259,AL       ;ISSUE SPECIFIC EOI FOR 8259
  696. X        pop     ds              ;GET BACK ENTERING DS
  697. X        pop     ax
  698. X        pop     bx
  699. X        pop     dx
  700. X        pop     cx
  701. X        sti
  702. X        iret
  703. X
  704. X_TEXT   ENDS
  705. X
  706. Xend
  707. X
  708. X
  709. END_OF_comport.s
  710. if test 20454 -ne `wc -c <comport.s`; then
  711.     echo shar: \"comport.s\" unpacked with wrong size!
  712. fi
  713. # end of overwriting check
  714. fi
  715. if test -f hsearch.c -a "${1}" != "-c" ; then 
  716.   echo shar: Will not over-write existing file \"hsearch.c\"
  717. else
  718. echo shar: Extracting \"hsearch.c\" \(15412 characters\)
  719. sed "s/^X//" >hsearch.c <<'END_OF_hsearch.c'
  720. X#include <ctype.h>        /* for case-insensitive version */
  721. X#include "hsearch.h"        /* join the parts that were broken up */
  722. X
  723. X#define    strcmp    istrcmp        /* for case-insensitive version */
  724. X
  725. Xstatic ELEMENT **Table = NULL;    /* pointer to dynamicly allocated table */
  726. Xstatic int Num_elem = -1;    /* number of elements */
  727. X
  728. Xextern char *calloc();
  729. X
  730. Xextern void hdestroy();
  731. Xextern int hcreate();
  732. Xextern ENTRY *hsearch();
  733. X
  734. Xstatic int hashit();
  735. X
  736. X/*
  737. X * table of first 1900 or so primes, for use in finding the right prime
  738. X * number to be the table size.  this table may be generally useful...
  739. X */
  740. X
  741. Xstatic unsigned short primetab[] = {
  742. X/*
  743. X * comment these out, so that table will always have a minimal size...
  744. X1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
  745. X*/
  746. X73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
  747. X157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
  748. X239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
  749. X331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
  750. X421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
  751. X509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607,
  752. X613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
  753. X709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
  754. X821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
  755. X919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019,
  756. X1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
  757. X1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201,
  758. X1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
  759. X1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409,
  760. X1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487,
  761. X1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579,
  762. X1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
  763. X1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777,
  764. X1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
  765. X1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993,
  766. X1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083,
  767. X2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179,
  768. X2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
  769. X2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381,
  770. X2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
  771. X2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609,
  772. X2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
  773. X2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789,
  774. X2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
  775. X2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001,
  776. X3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119,
  777. X3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229,
  778. X3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
  779. X3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457,
  780. X3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
  781. X3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637,
  782. X3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739,
  783. X3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853,
  784. X3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947,
  785. X3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073,
  786. X4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
  787. X4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273,
  788. X4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
  789. X4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517,
  790. X4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639,
  791. X4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733,
  792. X4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871,
  793. X4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969,
  794. X4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077,
  795. X5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189,
  796. X5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
  797. X5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431,
  798. X5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
  799. X5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651,
  800. X5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743,
  801. X5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851,
  802. X5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981,
  803. X5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091,
  804. X6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211,
  805. X6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311,
  806. X6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397,
  807. X6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553,
  808. X6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
  809. X6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781,
  810. X6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883,
  811. X6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991,
  812. X6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121,
  813. X7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237,
  814. X7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369,
  815. X7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507,
  816. X7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589,
  817. X7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699,
  818. X7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
  819. X7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937,
  820. X7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087,
  821. X8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209,
  822. X8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297,
  823. X8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431,
  824. X8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573,
  825. X8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681,
  826. X8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779,
  827. X8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887,
  828. X8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011,
  829. X9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137,
  830. X9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241,
  831. X9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371,
  832. X9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463,
  833. X9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601,
  834. X9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719,
  835. X9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817,
  836. X9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929,
  837. X9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069,
  838. X10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159,
  839. X10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259,
  840. X10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337,
  841. X10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459,
  842. X10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589,
  843. X10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667,
  844. X10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781,
  845. X10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889,
  846. X10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993,
  847. X11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113,
  848. X11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213,
  849. X11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317,
  850. X11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437,
  851. X11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527,
  852. X11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677,
  853. X11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783,
  854. X11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867,
  855. X11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959,
  856. X11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071,
  857. X12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161,
  858. X12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269,
  859. X12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379,
  860. X12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479,
  861. X12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553,
  862. X12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647,
  863. X12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757,
  864. X12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889,
  865. X12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967,
  866. X12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049,
  867. X13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163,
  868. X13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267,
  869. X13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397,
  870. X13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487,
  871. X13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619,
  872. X13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709,
  873. X13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799,
  874. X13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903,
  875. X13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011,
  876. X14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149,
  877. X14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281,
  878. X14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401,
  879. X14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489,
  880. X14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591,
  881. X14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699,
  882. X14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771,
  883. X14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869,
  884. X14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969,
  885. X14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101,
  886. X15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199,
  887. X15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289,
  888. X15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377,
  889. X15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473,
  890. X15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601,
  891. X15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679,
  892. X15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787,
  893. X15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889,
  894. X15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001,
  895. X16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097,
  896. X16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223,
  897. X16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349,
  898. X16361, 16363, 16369, 16381
  899. X};
  900. X
  901. X/* hcreate --- create a hash table at least howmany big */
  902. X
  903. Xint hcreate (howmany)
  904. Xregister unsigned int howmany;
  905. X{
  906. X    register int i, j;
  907. X
  908. X    /*
  909. X     * find first prime number >= howmany, and use it for table size
  910. X     */
  911. X
  912. X    if (Num_elem != -1)    /* already a table out there */
  913. X        hdestroy();    /* remove it */
  914. X
  915. X    j = sizeof (primetab) / sizeof (primetab[0]);
  916. X    for (i = 0; i < j; i++)
  917. X        if (primetab[i] >= howmany)
  918. X            break;
  919. X
  920. X    if (i >= j)    /* howmany bigger than any prime we have, use it */
  921. X        Num_elem = howmany;
  922. X    else
  923. X        Num_elem = primetab[i];
  924. X
  925. X    if ((Table = (ELEMENT **) calloc (Num_elem, sizeof (ELEMENT *))) == NULL)
  926. X        return (0);
  927. X    else
  928. X        return (1);
  929. X}
  930. X
  931. X/* idestroy --- destroy a single element on a chain */
  932. X
  933. Xstatic void idestroy (elem)
  934. XELEMENT *elem;
  935. X{
  936. X    if (elem != NULL)
  937. X    {
  938. X        idestroy (elem->next);
  939. X        free ((char *) elem);
  940. X    }
  941. X}
  942. X
  943. X/* hdestroy --- nuke the existing hash table */
  944. X
  945. Xvoid hdestroy()
  946. X{
  947. X    register unsigned int i;
  948. X
  949. X    if (Table != NULL)
  950. X    {
  951. X        /* free all the chains */
  952. X        for (i = 0; i < Num_elem; i++)
  953. X            idestroy (Table[i]);
  954. X
  955. X        /* now the table itself */
  956. X        free ((char *) Table);
  957. X        Num_elem = -1;
  958. X        Table = NULL;
  959. X    }
  960. X}
  961. X
  962. X/* hsearch --- lookup or enter an item in the hash table */
  963. X
  964. XENTRY *hsearch (entry, action)
  965. XENTRY entry;
  966. XACTION action;
  967. X{
  968. X    ELEMENT e;
  969. X    ELEMENT *ep = NULL;
  970. X    ELEMENT *ep2 = NULL;
  971. X    int index;
  972. X
  973. X    if (Table == NULL)
  974. X        return (NULL);
  975. X
  976. X    index = hashit (entry.key);
  977. X    if (Table[index] == NULL)    /* nothing there */
  978. X    {
  979. X        if (action == FIND)
  980. X            return (NULL);
  981. X        else
  982. X        {
  983. X            /* add it to the table */
  984. X            e.item = entry;
  985. X            e.next = NULL;
  986. X            if ((Table[index] = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
  987. X                return (NULL);
  988. X            *Table[index] = e;
  989. X            return (& Table[index]->item);
  990. X        }
  991. X    }
  992. X    else
  993. X    {
  994. X        /* something in bucket, see if already on chain */
  995. X        for (ep = Table[index]; ep != NULL; ep = ep->next)
  996. X        {
  997. X            if (strcmp (ep->item.key, entry.key) == 0)
  998. X            {
  999. X                if (action == ENTER)
  1000. X                    ep->item.data = entry.data;
  1001. X                    /* already there, just change data */
  1002. X                /* or action was just find it */
  1003. X                return (& ep->item);
  1004. X            }
  1005. X            else
  1006. X                ep2 = ep;
  1007. X        }
  1008. X        /* at this point, item was not in table */
  1009. X        /* ep2 points at last element on the list */
  1010. X        if (action == ENTER)
  1011. X        {
  1012. X            if ((ep2->next = (ELEMENT *) calloc (1, sizeof (ELEMENT))) == NULL)
  1013. X                return (NULL);
  1014. X            ep2->next->item = entry;
  1015. X            ep2->next->next = NULL;
  1016. X            return (& ep2->next->item);
  1017. X        }
  1018. X        else
  1019. X            return (NULL);
  1020. X    }
  1021. X    /*NOTREACHED*/
  1022. X}
  1023. X
  1024. X/* hashit --- do the hashing algorithm */
  1025. X
  1026. X/*
  1027. X * algorithm is sum of string elements, plus string length
  1028. X * mod table size.
  1029. X *
  1030. X * made case insensitive for hyphenation program
  1031. X */
  1032. X
  1033. Xstatic int hashit (text)
  1034. Xregister char *text;
  1035. X{
  1036. X    register long int sum = 0;
  1037. X    register int i;
  1038. X    register int kludge;
  1039. X
  1040. X    for (i = 0; (kludge = text[i]) != '\0'; i++)
  1041. X        sum += (isupper(kludge) ? tolower(kludge) : kludge);
  1042. X    sum += i;
  1043. X
  1044. X    return (sum % Num_elem);
  1045. X}
  1046. X
  1047. END_OF_hsearch.c
  1048. if test 15412 -ne `wc -c <hsearch.c`; then
  1049.     echo shar: \"hsearch.c\" unpacked with wrong size!
  1050. fi
  1051. # end of overwriting check
  1052. fi
  1053. if test -f hsearch.h -a "${1}" != "-c" ; then 
  1054.   echo shar: Will not over-write existing file \"hsearch.h\"
  1055. else
  1056. echo shar: Extracting \"hsearch.h\" \(445 characters\)
  1057. sed "s/^X//" >hsearch.h <<'END_OF_hsearch.h'
  1058. X/* hsearch.c --- PD simple implementation of System V hsearch(3c) routine */
  1059. X
  1060. X/* 
  1061. X* All I (WZV) changed was: 
  1062. X* put this part of the original hsearch.c in a separate file
  1063. X* make the lookup and hashing algorithms case-insensitive
  1064. X*/
  1065. X
  1066. X#include <stdio.h>
  1067. X
  1068. Xtypedef struct entry {
  1069. X    char *key;
  1070. X    char *data;
  1071. X    } ENTRY;
  1072. X
  1073. Xtypedef enum {
  1074. X    FIND,
  1075. X    ENTER
  1076. X    } ACTION;
  1077. X
  1078. Xtypedef struct element {
  1079. X    ENTRY    item;
  1080. X    struct element *next;
  1081. X    } ELEMENT;
  1082. X
  1083. XENTRY *hsearch();
  1084. END_OF_hsearch.h
  1085. if test 445 -ne `wc -c <hsearch.h`; then
  1086.     echo shar: \"hsearch.h\" unpacked with wrong size!
  1087. fi
  1088. # end of overwriting check
  1089. fi
  1090. if test -f pager.c -a "${1}" != "-c" ; then 
  1091.   echo shar: Will not over-write existing file \"pager.c\"
  1092. else
  1093. echo shar: Extracting \"pager.c\" \(14137 characters\)
  1094. sed "s/^X//" >pager.c <<'END_OF_pager.c'
  1095. X/*++
  1096. X/* NAME
  1097. X/*      pager 3
  1098. X/* SUMMARY
  1099. X/*      pager for text files
  1100. X/* PROJECT
  1101. X/*      pc-mail
  1102. X/* PACKAGE
  1103. X/*      mailsh
  1104. X/* SYNOPSIS
  1105. X/*      #include "pager.h"
  1106. X/*
  1107. X/*      File *open_pager()
  1108. X/*
  1109. X/*      void close_pager(p)
  1110. X/*      File *p;
  1111. X/*
  1112. X/*      void set_pager(p)
  1113. X/*      File *p;
  1114. X/*
  1115. X/*      void app_pager(p,s)
  1116. X/*      File *p;
  1117. X/*      char *s;
  1118. X/*
  1119. X/*      void del_pager(p)
  1120. X/*      File *p;
  1121. X/*
  1122. X/*      void mesg_pager(p,m)
  1123. X/*      File *p;
  1124. X/*      char *m[];
  1125. X/*
  1126. X/*      int scan_pager(p,fmt[,args])
  1127. X/*      File *p;
  1128. X/*
  1129. X/*      void sort_pager(p,dir)
  1130. X/*      File *p;
  1131. X/*
  1132. X/*      int cp_pager(path)
  1133. X/*      char *path;
  1134. X/*
  1135. X/*      int pr_pager()
  1136. X/*
  1137. X/*      int rd_pager(p,path)
  1138. X/*      File *p;
  1139. X/*      char *path;
  1140. X/*
  1141. X/*      char *gets_pager();
  1142. X/*
  1143. X/*      void puts_pager(s);
  1144. X/*      char *s;
  1145. X/*
  1146. X/*      int ds_pager()
  1147. X/*
  1148. X/*      int pr_pager()
  1149. X/*
  1150. X/*      int up_pager()
  1151. X/*
  1152. X/*      int dn_pager()
  1153. X/*
  1154. X/*      int pu_pager()
  1155. X/*
  1156. X/*      int pd_pager()
  1157. X/* DESCRIPTION
  1158. X/*      The pager provides acces to a pager file which is displayed
  1159. X/*      on the screen in the middle window. Some functions operate
  1160. X/*    on what is called the "current" pager file. All functions 
  1161. X/*    have access to the contents of the middle screen window only.
  1162. X/*
  1163. X/*      open_pager() creates a new (empty) pager file. The return value
  1164. X/*      should be used in subsequent accesses to the file. Sets the
  1165. X/*      current file.
  1166. X/*
  1167. X/*      close_pager() releases storage for a pager file. Sets the
  1168. X/*      current file to none if that is the one being deleted.
  1169. X/*
  1170. X/*      app_pager() appends a new line of text to the end of a pager file.
  1171. X/*      Sets the current file.
  1172. X/*
  1173. X/*      del_pager() deletes the line at the current cursor position. Sets the
  1174. X/*      current file.
  1175. X/*
  1176. X/*      mesg_pager() invokes app_pager() to copy a null-terminated array of 
  1177. X/*    strings to a pager file. Since it invokes app_pager(), the current
  1178. X/*    pager file is set as well. Pager files filled by mesg-pager()
  1179. X/*    will not be displayed with an '-- end of display --' line at their end.
  1180. X/*
  1181. X/*      ins_pager() inserts a line at the current cursor position. Sets the
  1182. X/*      current file.
  1183. X/*
  1184. X/*      scan_pager() takes similar arguments as scanf(3), reads from the 
  1185. X/*      line at the current cursor position and returns the number of 
  1186. X/*      successfull conversions done. Does not set the current file.
  1187. X/*
  1188. X/*      sort_pager() sorts a file alphabetically. Sets the current file.
  1189. X/*      The dir argument selects the direction of sort (FORW_SORT, BACK_SORT).
  1190. X/*
  1191. X/*      set_pager() sets the current file.
  1192. X/*
  1193. X/*      gets_pager() returns a pointer to the current line in the
  1194. X/*      current file, or a null pointer is there is none.
  1195. X/*
  1196. X/*      puts_pager() replaces the current line in the current file.
  1197. X/*
  1198. X/*      cp_pager() copies the contents of current pager file
  1199. X/*      to a normal (external) file. It returns a nonzero status if
  1200. X/*      an error occurred (bad path, write error,...).
  1201. X/*
  1202. X/*      pr_pager() copies the current pager file to the printer.
  1203. X/*
  1204. X/*      rd_pager() appends a permanent file to the current pager file.
  1205. X/*      It returns a nonzero status if an error occurred. Sets the current file.
  1206. X/*    rd_pager() reads through the ascf(3) ascii filter, so that it is 
  1207. X/*    suitable for viewing word-processor files.
  1208. X/*
  1209. X/*      up_pager() moves the cursor one line up, if there is one. The
  1210. X/*    screen is scrolled when the cursor was at the top of the screen.
  1211. X/*
  1212. X/*      dn_pager moves the cursor one line down, if there is one. The
  1213. X/*    screen is scrolled when the cursor was at the bottom of the screen.
  1214. X/*
  1215. X/*      pu_pager() displays a page of text that precedes the one on the
  1216. X/*      screen, or as much as there is.
  1217. X/*
  1218. X/*      pd_pager() displays the next page of text, or as much as there is.
  1219. X/* FUNCTIONS AND MACROS
  1220. X/*      printcl(), printat(), beep(), propen(), prclose(),ascopen(), 
  1221. X/*    ascclose(), ascget()
  1222. X/* SEE ALSO
  1223. X/*      path(3), window(3), window(5), asc(3)
  1224. X/* DIAGNOSTICS
  1225. X/*      The buzzer makes noise when attempt is made to move the
  1226. X/*      cursor beyond the beginning or end of the pager file.
  1227. X/*      The program aborts with an error message if references are made
  1228. X/*      to the "current file" or "current line" if there is none.
  1229. X/* BUGS
  1230. X/*      It looks a lot like an editor, but it isn't.
  1231. X/*
  1232. X/*    No optimization. It just overwrites the whole middle window.
  1233. X/* AUTHOR(S)
  1234. X/*      W.Z. Venema
  1235. X/*      Eindhoven University of Technology
  1236. X/*      Department of Mathematics and Computer Science
  1237. X/*      Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
  1238. X/* CREATION DATE
  1239. X/*      Fri Apr  3 22:06:00 GMT+1:00 1987
  1240. X/* LAST MODIFICATION
  1241. X/*    Mon Apr  4 23:46:06 MET 1988
  1242. X/* VERSION/RELEASE
  1243. X/*    1.3
  1244. X/*--*/
  1245. X
  1246. X#include "defs.h"
  1247. X#include "window.h"
  1248. X#include "pager.h"
  1249. X#include "path.h"
  1250. X#include "ascf.h"
  1251. X
  1252. Xhidden File *curfile = NULL;            /* head of the current file */
  1253. X
  1254. X/* open_pager - create pager file and set current file */
  1255. X
  1256. Xpublic File *open_pager()
  1257. X{
  1258. X    register File *p = curfile = (File *) myalloc(sizeof(File));
  1259. X
  1260. X    p->top = p->curr = p->head = p->last = NULL;
  1261. X    p->opts = 0;
  1262. X    return(p);
  1263. X}
  1264. X
  1265. X/* close_pager - release memory in a pager file */
  1266. X
  1267. Xpublic void close_pager(p)
  1268. Xregister File *p;
  1269. X{
  1270. X    register Line *q;
  1271. X
  1272. X    if (p) {
  1273. X    for (q = p->head; q; q = q->next)    /* release lines */
  1274. X        free((char *)q);
  1275. X    if (curfile == p)            /* unset current file */
  1276. X        curfile = 0;
  1277. X    free((char *)p);            /* release header */
  1278. X    }
  1279. X}
  1280. X
  1281. X/* app_pager - append line at end of file and set current file */
  1282. X
  1283. Xpublic app_pager(p,s)
  1284. Xregister File *p;
  1285. Xchar *s;
  1286. X{
  1287. X    register Line *l = (Line *) myalloc(sizeof(Line)+strlen(s));
  1288. X
  1289. X    if (p->head == 0) {                         /* first line in the file */
  1290. X    p->head = p->top = p->curr = l;
  1291. X    } else {                                    /* real append */
  1292. X    p->last->next = l;
  1293. X    }
  1294. X    l->next = NULL;                             /* since it is last */
  1295. X    l->prev = p->last;                          /* since it is last */
  1296. X    p->last = l;                                /* since it is last */
  1297. X
  1298. X    strcpy(l->line,s);                          /* copy the line */
  1299. X
  1300. X    curfile = p;                                /* set current file */
  1301. X}
  1302. X
  1303. X/* del_pager - delete line at cursor and set current file (untested!) */
  1304. X
  1305. Xpublic void del_pager(p)
  1306. Xregister File *p;
  1307. X{
  1308. X    register Line *l = p->curr;
  1309. X
  1310. X    if (l) {
  1311. X    if (l->prev)
  1312. X        l->prev->next = l->next;
  1313. X    if (l->next)
  1314. X        l->next->prev = l->prev;
  1315. X    if (l == p->head)
  1316. X        p->curr = p->head = l->next;
  1317. X    if (l == p->top)
  1318. X        p->curr = p->top  = l->next ? l->next : l->prev;
  1319. X    if (l == p->last)
  1320. X        p->curr = p->last = l->prev;
  1321. X    if (l == p->curr)
  1322. X        p->curr = l->next;
  1323. X    free((char *) l);
  1324. X    }
  1325. X    curfile = p;
  1326. X}
  1327. X
  1328. X/* scan_pager - read from line at cursor and set current file */
  1329. X
  1330. X/* VARARGS2 */
  1331. X
  1332. Xpublic int scan_pager(p,fmt,a1,a2,a3,a4)
  1333. XFile *p;
  1334. Xchar *fmt;
  1335. Xlong a1,a2,a3,a4;
  1336. X{
  1337. X    return(p && p->curr ? sscanf(p->curr->line,fmt,a1,a2,a3,a4) : 0);
  1338. X}
  1339. X
  1340. X/* set_pager - set the current file; use with care */
  1341. X
  1342. Xpublic void set_pager(p)
  1343. XFile *p;
  1344. X{
  1345. X    curfile = p;
  1346. X}
  1347. X
  1348. X/*
  1349. X* The following functions provide an easy interface to the keyboard
  1350. X* interpreter routines. The keyboard driver just associates a key stroke
  1351. X* with a function call, does not care what a function does and has
  1352. X* almost no facility for passing function arguments.
  1353. X* Although the keyboard interpreter manipulates cursor and page coordinates 
  1354. X* when the some keys are hit, it never knows which keys affect what
  1355. X* the user sees on the screen.
  1356. X* That explains why the following functions rely on the above ones
  1357. X* for setting the "current file".
  1358. X* It may also explain why the above routines do not immediately update
  1359. X* the terminal screen, whereas the routines below do.
  1360. X*/
  1361. X
  1362. X/* ds_pager - display a page of the current pager file */
  1363. X
  1364. Xpublic int ds_pager()
  1365. X{
  1366. X    static char endline[] = "-- end of display --";
  1367. X
  1368. X    if (curfile && curfile->curr) {
  1369. X    register Line *p;
  1370. X    register int k;
  1371. X
  1372. X    for (p = curfile->top,k = 0; p && k < wsize[MID]; p = p->next)
  1373. X        k += p->llen = printcl(MID,p->lineno = k,p->line);
  1374. X    if (k < wsize[MID])
  1375. X        printcl(MID,k++,(curfile->opts & PG_NOEND) ? "" : endline);
  1376. X    while (k < wsize[MID])
  1377. X        printcl(MID,k++,"");
  1378. X    printat(MID,curfile->curr->lineno,"");
  1379. X    } else {
  1380. X    register int k;
  1381. X
  1382. X    printcl(MID,0,(curfile->opts & PG_NOEND) ? "" : endline);
  1383. X    for (k = 1; k < wsize[MID]; k++)
  1384. X        printcl(MID,k,"");
  1385. X    printat(MID,0,"");
  1386. X    }
  1387. X    return(0);  /* screen up-to-date */
  1388. X}
  1389. X
  1390. X/* up_pager - up-arrow key hit. check cursor position */
  1391. X
  1392. Xpublic int up_pager()
  1393. X{
  1394. X    register Line *p = curfile ? curfile->curr : 0;
  1395. X
  1396. X    if (p == 0 || p->prev == 0) {
  1397. X    beep();
  1398. X    } else {
  1399. X    if (p->lineno == 0)
  1400. X        pu_pager();
  1401. X    printat(MID,(curfile->curr = p->prev)->lineno,"");
  1402. X    }
  1403. X    return(0);
  1404. X}
  1405. X
  1406. X/* dn_pager - down-arrow key hit. check cursor position */
  1407. X
  1408. Xpublic int dn_pager()
  1409. X{
  1410. X    register Line *p = curfile ? curfile->curr : 0;
  1411. X
  1412. X    if (p == 0 || p->next == 0) {
  1413. X    beep();
  1414. X    } else {
  1415. X    if (p->lineno+p->llen >= wsize[MID])
  1416. X        pd_pager();
  1417. X    printat(MID,(curfile->curr = p->next)->lineno,"");
  1418. X    }
  1419. X    return(0);
  1420. X}
  1421. X
  1422. X/* pu_pager - display preceding page of info */
  1423. X
  1424. Xpublic int pu_pager()
  1425. X{
  1426. X    register Line *p;
  1427. X    register int k;
  1428. X
  1429. X    if (curfile && (p = curfile->top) && curfile->top->prev) {
  1430. X    for (k = 0; k < wsize[MID] && p; k += p->llen,p = p->prev)
  1431. X        curfile->top = p;
  1432. X    curfile->curr = curfile->top;
  1433. X    ds_pager();
  1434. X    } else {
  1435. X    beep();
  1436. X    }
  1437. X    return(0);
  1438. X}
  1439. X
  1440. X/* pd_pager - display next page of info */
  1441. X
  1442. Xpublic int pd_pager()
  1443. X{
  1444. X    register Line *p = curfile ? curfile->top : 0;
  1445. X    register int k;
  1446. X    register Line *dummy;
  1447. X
  1448. X    for (k = 0; k < wsize[MID] && p; k += p->llen,p = p->next)
  1449. X    dummy = p;
  1450. X    if (p) {
  1451. X    curfile->curr = curfile->top = dummy;
  1452. X    ds_pager();
  1453. X    } else {
  1454. X    beep();
  1455. X    }
  1456. X    return(0);
  1457. X}
  1458. X
  1459. X/*
  1460. X* The following functions copy permanent files to pager file
  1461. X* and vice-versa. There is a limited error detection facility
  1462. X* in the form of nonzero return values.
  1463. X*/
  1464. X
  1465. X/* cp_pager - copy current pager file to permanent file */
  1466. X
  1467. Xpublic int cp_pager(path)
  1468. Xchar *path;
  1469. X{
  1470. X    register FILE *fp;
  1471. X
  1472. X    if (curfile && (fp = fopen(path,"w"))) {
  1473. X    register Line *pp;
  1474. X    int err;
  1475. X    for (pp = curfile->head; pp; pp = pp->next)
  1476. X        fputs(pp->line,fp),putc('\n',fp);
  1477. X    err = ferror(fp);
  1478. X    fclose(fp);
  1479. X    return(err);
  1480. X    } else {
  1481. X    return(-1);
  1482. X    }
  1483. X}
  1484. X
  1485. X/* pr_pager - print pager file on default printer */
  1486. X
  1487. Xpublic int pr_pager()
  1488. X{
  1489. X    register FILE *fp;
  1490. X
  1491. X    if (curfile && (fp = propen())) {
  1492. X    register Line *pp;
  1493. X    int err;
  1494. X    for (pp = curfile->head; pp; pp = pp->next)
  1495. X        fputs(pp->line,fp),putc('\n',fp);
  1496. X    err = ferror(fp);
  1497. X    prclose(fp);
  1498. X    return(err);
  1499. X    } else {
  1500. X    return(-1);
  1501. X    }
  1502. X}
  1503. X
  1504. X/* rd_pager - copy ordinary file via filter to pager file */
  1505. X
  1506. Xpublic int rd_pager(p,path)
  1507. XFile *p;
  1508. Xchar *path;
  1509. X{
  1510. X    register FILE *fp;
  1511. X
  1512. X    if (p && (fp = ascopen(path,"r"))) {        /* init the filter */
  1513. X    char buf[BUFSIZ];
  1514. X    char *cp = buf;
  1515. X    register int c;
  1516. X    int err;
  1517. X
  1518. X    while ((c = ascget(fp)) != EOF) {        /* copy to pager file */
  1519. X        if (c == '\n' || cp == buf+BUFSIZ-1) {
  1520. X        *cp = 0;
  1521. X        app_pager(p,cp = buf);                  /* line by line */
  1522. X        } else {
  1523. X        *cp++ = c; 
  1524. X        }
  1525. X    }
  1526. X    if (cp > buf) {                    /* anything left? */
  1527. X        *cp = '\0';
  1528. X        app_pager(p,buf);
  1529. X    }
  1530. X    err = ferror(fp);                /* check for errors */
  1531. X    ascclose(fp);
  1532. X    return(err);
  1533. X    } else {
  1534. X    return(-1);
  1535. X    }
  1536. X}
  1537. X
  1538. X/* fwdcmp, revcmp - compare lexical order of lines */
  1539. X
  1540. Xhidden int fwdcmp(l1,l2)
  1541. XLine **l1,**l2;
  1542. X{
  1543. X    return(strcmp((*l1)->line,(*l2)->line));
  1544. X}
  1545. X
  1546. Xhidden int revcmp(l1,l2)
  1547. XLine **l1,**l2;
  1548. X{
  1549. X    return(strcmp((*l2)->line,(*l1)->line));
  1550. X}
  1551. X
  1552. X/* sort_pager - sort a pager file, a boring thing */
  1553. X
  1554. Xpublic void sort_pager(pp,dir)
  1555. XFile *pp;
  1556. Xint dir;
  1557. X{
  1558. X    register Line *l;
  1559. X    register int i;
  1560. X    int lines;
  1561. X    Line **lvec;
  1562. X
  1563. X    for (i = 0,l = pp->head; l; l = l->next)            /* count nbr of lines */
  1564. X    i++;
  1565. X
  1566. X    if (i <= 1)                                         /* no work */
  1567. X    return;
  1568. X
  1569. X    lvec = (Line **) myalloc((lines = i)*sizeof(*lvec));/* allocate vector */
  1570. X
  1571. X    for (i = 0,l = pp->head; l; l = l->next)            /* fill vector */
  1572. X    lvec[i++] = l;
  1573. X
  1574. X    qsort((char *) lvec,lines,sizeof(*lvec),dir == FORW_SORT ? fwdcmp : revcmp);
  1575. X
  1576. X    for (i = 0; i < lines-1; i++)                       /* fix forward links */
  1577. X    lvec[i]->next = lvec[i+1];
  1578. X    lvec[i]->next = NULL;
  1579. X
  1580. X    lvec[0]->prev = NULL;                               /* fix backward links */
  1581. X    for (i = 1; i < lines; i++)
  1582. X    lvec[i]->prev = lvec[i-1];
  1583. X
  1584. X    pp->head = pp->top = pp->curr = lvec[0];            /* fix file header */
  1585. X    pp->last = lvec[lines-1];
  1586. X
  1587. X    free((char *) lvec);                                /* release vector */
  1588. X
  1589. X    curfile = pp;                                       /* set current file */
  1590. X}
  1591. X
  1592. X/* gets_pager - return current line in current file */
  1593. X
  1594. Xpublic char *gets_pager()
  1595. X{
  1596. X    return(curfile && curfile->curr ? curfile->curr->line : 0);
  1597. X}
  1598. X
  1599. X/* puts_pager - replace line (cleanup this mess) */
  1600. X
  1601. Xpublic void puts_pager(s)
  1602. Xchar *s;
  1603. X{
  1604. X    if (curfile == 0 || curfile->curr == 0) {   /* no-no if there is no line */
  1605. X    fatal("puts_pager: no current file");
  1606. X    } else {
  1607. X    register Line *old = curfile->curr;     /* get current line */
  1608. X    register Line *new = (Line *) myalloc(sizeof(Line)+strlen(s));
  1609. X    new->prev = old->prev;                  /* fill it in */
  1610. X    new->next = old->next;
  1611. X    new->lineno = old->lineno;
  1612. X    strcpy(new->line,s);
  1613. X    if (new->next)                          /* check next line */
  1614. X        new->next->prev = new;
  1615. X    if (new->prev)                          /* check previous line */
  1616. X        new->prev->next = new;
  1617. X    if (old == curfile->head)               /* check file head */
  1618. X        curfile->head = new;
  1619. X    if (old == curfile->top)                /* check file display */
  1620. X        curfile->top = new;
  1621. X    if (old == curfile->last)               /* check file tail */
  1622. X        curfile->last = new;
  1623. X    free((char *) curfile->curr);           /* release old line */
  1624. X    curfile->curr = new;                    /* set current line */
  1625. X    }
  1626. X}
  1627. X
  1628. X/* mesg_pager - copy null-terminated array of strings to pager file */
  1629. X
  1630. Xpublic void mesg_pager(pp,msg)
  1631. Xregister File *pp;
  1632. Xregister char **msg;
  1633. X{
  1634. X    pp->opts |= PG_NOEND;            /* suppress end marker */
  1635. X
  1636. X    while (*msg)
  1637. X    app_pager(pp,*msg++);
  1638. X}
  1639. END_OF_pager.c
  1640. if test 14137 -ne `wc -c <pager.c`; then
  1641.     echo shar: \"pager.c\" unpacked with wrong size!
  1642. fi
  1643. # end of overwriting check
  1644. fi
  1645. echo shar: End of archive 1 \(of 8\).
  1646. cp /dev/null ark1isdone
  1647. MISSING=""
  1648. for I in 1 2 3 4 5 6 7 8 ; do
  1649.     if test ! -f ark${I}isdone ; then
  1650.     MISSING="${MISSING} ${I}"
  1651.     fi
  1652. done
  1653. if test "${MISSING}" = "" ; then
  1654.     echo You have unpacked all 8 archives.
  1655.     rm -f ark[1-9]isdone
  1656. else
  1657.     echo You still need to unpack the following archives:
  1658.     echo "        " ${MISSING}
  1659. fi
  1660. ##  End of shell archive.
  1661. exit 0
  1662. -- 
  1663. uucp:    mcvax!eutrc3!wswietse    | Eindhoven University of Technology
  1664. bitnet:    wswietse@heithe5    | Dept. of Mathematics and Computer Science
  1665. surf:    tuerc5::wswietse    | Eindhoven, The Netherlands.
  1666.